﻿#pragma once

#include "Containers/Containers.h"

#include "Misc/StdHead.h"
#include "Misc/Name.h"
#include "Containers/Containers.h"

#include "Primitive/DebugLine.h"
#include "Framework/Subsystem.h"
#include "Framework/SubsystemManager.h"

#include "Physics/PhysicalScene.h"

#include "Object/Object.h"
#include "Scene/SceneNode.h"
#include "Scene/SceneNodeComponent.h"

#include "Containers/ThreadSafePtr.h"

#include "Render/Scene/CameraParameters.h"
#include "Render/Scene/RenderScene.h"

#include "Event/MouseEvent.h"
#include "Event/KeyboardEvent.h"
#include "Scene.m.h"


class CRenderScene;
class CPhysicalWorld;
class CPointLightComponent;

class RubsystemManager;
class RSceneSubsystem;
class RViewportWidget;
class RInputComponent;

RCLASS()
class WHENGINE_API RScene : public RObject
{
    ROBJECT

    RScene();
    void FirstTimeInitializeObject() override;
    ~RScene(); 
public:


    //TVector<TSharedObjectPtr<RStaticMeshComponent>> Instances;
    TVector<std::shared_ptr<CDebugLine>> DebugLines;

    RFUNCTION()
    void BeginPlay();

    void EndPlay();

    void Tick(float DeltaSeconds);

    void Paint(CRenderScene* InRenderSceneData);

    bool IsPlaying()
    {
        return bPlaying;
    }
private:
    bool bPlaying=false;

public:
    template<typename NodeType>
    TSharedObjectPtr<NodeType> NewNode()
    {
        auto Node=NewObject<NodeType>(this);
        AddNode(Node);
        return Node;
    }

    void AddNode(TSharedObjectPtr<RSceneNode> InNode);

    int64_t GetNodeNum();
    TSharedObjectPtr<RSceneNode> GetNode(int64_t InNodeIndex); 
private:
    RFIELD()
    TVector<TSharedObjectPtr<RSceneNode>>  Nodes;

public:
    // void RegisterPysicalBody(std::shared_ptr<CPhysicalBody> Body);
    // void UnregisterPysicalBody(std::shared_ptr<CPhysicalBody> Body);

    TSharedObjectPtr<RPhysicalScene>  GetPhysicalScene()
    {
        return PhysicalScene;
    }

    //绘制碰撞体
    void PaintCollider(CRenderScene* InRenderSceneData);

protected:
    RFIELD()
    TSharedObjectPtr<RPhysicalScene> PhysicalScene;

public:

    TMultiCastDelegate<> OnBeginPlay;

    template<typename SceneNodeType>
    TSharedObjectPtr<SceneNodeType> FindNode()
    {
        RSceneNodePtr Node=FindNodeByClass(SceneNodeType::StaticClass());
        return TSharedObjectPtr<SceneNodeType>(Node);
    }

    RSceneNodePtr FindNodeByClass(CClass* InClass);

    template<typename SubsystemType>
    SubsystemType* GetSubsystem()
    {
        if(bIsDestroying)
        {
            return nullptr;
        }
        
        if(!SubsystemManager)
        {
            return nullptr;
        }

        return SubsystemManager->GetSubsystem<SubsystemType>();
    }

protected:

    RFIELD()
    TSharedObjectPtr<RSubsystemManager> SubsystemManager;
    
    bool bIsDestroying=false;

public:

    template<typename ComponentType>
    TVector<TSharedObjectPtr<ComponentType>> GetComponents()
    {
        TVector<TSharedObjectPtr<ComponentType>> AllComponents;
        for(auto& Node: Nodes)
        {
            AllComponents.Append(Node->GetComponents<ComponentType>());
        }
        return AllComponents;
    }

};